/*
 * @Author: yoola youlikesoilove@qq.com
 * @Date: 2024-11-28 22:53:06
 * @LastEditors: yoola youlikesoilove@qq.com
 * @LastEditTime: 2024-12-24 23:45:16
 * @FilePath: \CrabSystemProject\src\ModuleCenter\main.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置:
 * https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <memory>  // 共享内存
#include "moduleComm.hpp"
#include <thread>
#include <chrono>  // 用于 std::chrono::milliseconds
#include <list>
#include <string>
#include <nlohmann/json.hpp>
#include "ConfigManager.hpp"
#include "simpleLoger.hpp"

// 用于request pic
#ifndef CAPPICFUNC
#define CAPPICFUNC

#include <iostream>
#include <thread>
#include <chrono>
#include <cstring>  // for std::strerror
#include <errno.h>  // for errno
#include <fcntl.h>  // for open
#include <atomic>
#include <sys/stat.h>  // for mkfifo
#include <unistd.h>    // POSIX API函数，如 unlink、read 和 close
#include <fcntl.h>     // 如果有open、O_RDONLY 等使用
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>  //select
#include <errno.h>
#include <csignal>  // for signal handling
#include <iomanip>
#include <sstream>
#include <string>
const char *pipe_path = "/tmp/capture_pipe";
std::atomic<bool> running(true);  // 用于控制线程运行状态
void signal_handler(int signal) {
    running = false;  // 设置为停止运行状态
    exit(1);
}
std::string formatWeight(float weight) {
    // 检查输入范围
    if (weight < 0 || weight > 999.9) {
        throw std::out_of_range("Weight must be between 0 and 999.9.");
    }
    std::ostringstream oss;
    // 设置格式，固定宽度为6（包含小数点），填充0，小数点后保留1位
    oss << "CAP_" << std::setfill('0') << std::setw(6) << std::fixed << std::setprecision(1) << weight;
    oss.copyfmt(std::ios(nullptr));
    return oss.str();
}
int send_capture_signal(float weight) {
    int write_repeat_times = 0;
    while (running) {
        // 尝试以只写模式打开命名管道
        int w_fd = open(pipe_path, O_WRONLY | O_NONBLOCK);  // 非阻塞式
        if (write_repeat_times >= 10) {
            close(w_fd);  // 关闭写入管道
            return 1;
        } else if (w_fd == -1) {
            write_repeat_times++;
            OUTPUT_ERRR << "Failed to open named pipe for reading: " << std::strerror(errno) << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));  // 等待重试
            close(w_fd);                                                  // 关闭写入管道
            continue;                                                     // 继续循环
        }

        // const char *message = "CAP_559";  // 要发送的消息
        std::string message = formatWeight(weight);

        if (write(w_fd, message.c_str(), message.length()) == -1) {
            write_repeat_times++;
            OUTPUT_ERRR << "Failed to write to named pipe: " << std::strerror(errno) << std::endl;
            close(w_fd);  // 关闭写入管道
            continue;
        } else {
            OUPUT_INFO << "wirting ok!" << std::endl;
            close(w_fd);  // 关闭写入管道
        }

        int r_fd = open(pipe_path, O_RDONLY);  // 以只读模式打开响应管道

        // 设置超时时间
        struct timeval timeout;
        timeout.tv_sec = 10;  // 超时 10 秒
        timeout.tv_usec = 0;

        // 准备监控的文件描述符集合
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(r_fd, &readfds);

        // 使用 select 等待输入或超时
        int retval = select(r_fd + 1, &readfds, NULL, NULL, &timeout);
        if (retval == -1) {
            perror("select()");
        } else if (retval == 0) {
            OUPUT_INFO << "Timeout occurred! No data after " << timeout.tv_sec << " seconds." << std::endl;
            return 1;
        } else {
            // 读取数据
            char buffer[256];
            ssize_t bytesRead = read(r_fd, buffer, sizeof(buffer) - 1);  // 读取数据
            buffer[bytesRead] = '\0';                                    // 确保字符串结束
            OUPUT_INFO << "Received from server: " << buffer << std::endl;
            return 0;
        }
    }
    return 0;
}

#endif

ConfigManager configManager("config__business.json");
ConfigStruct config;
std::list<std::shared_ptr<RS485SerialPortBASE>> FuncList;
std::shared_ptr<RS485SerialPortBASE> get_ptr(const std::string ptr_name) {
    for (auto p_func : FuncList) {
        if (p_func->m_module_name == ptr_name) {
            return p_func;
        }
    }
    return nullptr;
}

bool create_func_list(void) {
    if (config.m_temperature_config.m_isopen) {
        OUPUT_INFO << "功能列表插入温度传感器" << std::endl;
        FuncList.push_back(std::make_shared<temper_Reader>());
    }
    if (config.m_weight_config.m_isopen) {
        OUPUT_INFO << "功能列表插入称重传感器" << std::endl;
        FuncList.push_back(std::make_shared<Weight_Reader>());
    }
    if (config.m_IO_controller_config.m_isopen) {
        OUPUT_INFO << "功能列表插入IO控制器" << std::endl;
        FuncList.push_back(std::make_shared<IO_Control>());
    }
    return true;
}

bool init_dev(void) {
    for (auto p_func : FuncList) {
        if (p_func->init()) {
            OUPUT_INFO << p_func->m_module_name << ": 初始化成功！" << std::endl;
        } else {
            OUPUT_INFO << p_func->m_module_name << ": 初始化失败！" << std::endl;
            // return false;
        }
    }
    return true;
}

bool check_online(void) {
    for (auto p_func : FuncList) {
        if (p_func->CheckDevOnline()) {
            OUPUT_INFO << p_func->m_module_name << ": 设备在线！" << std::endl;
        } else {
            OUPUT_INFO << p_func->m_module_name << ": 设备离线！" << std::endl;
        }
    }
    return true;
}

bool read_data(void) {
    for (auto p_func : FuncList) {
        p_func->ReadData();
    }
    return true;
}

void print_value(void) {
    for (auto p_func : FuncList) {
        // if (p_func->m_module_name == "temperature-reader") {
        //     OUPUT_INFO<< "读取温度数据为： " <<
        //     std::dynamic_pointer_cast<temper_Reader>(p_func)->GetRealTemper()<< std::endl;
        // } else if (p_func->m_module_name == "temperature-reader") {
        //     /* code */
        // }
        // 检查并强制转换为实际的类型
        if (p_func->GetTypeInfo() == typeid(RS485SerialPort<float>)) {
            auto derivedPtr = std::dynamic_pointer_cast<RS485SerialPort<float>>(p_func);
            if (derivedPtr) {
                OUPUT_INFO << p_func->m_module_name << " value is : " << derivedPtr->GetData() << std::endl;
            }
        } else if (p_func->GetTypeInfo() == typeid(RS485SerialPort<uint8_t>)) {
            auto derivedPtr = std::dynamic_pointer_cast<RS485SerialPort<uint8_t>>(p_func);
            if (derivedPtr) {
                OUPUT_INFO << p_func->m_module_name << " value is : " << std::setw(2) << std::setfill('0') << std::hex
                           << static_cast<int>(derivedPtr->GetData()) << std::dec << std::endl;
            }
        } else {
            OUPUT_INFO << p_func->m_module_name << " : type is " << typeid(p_func->GetTypeInfo()).name()
                       << " : can't find object! can't print value!" << std::endl;
        }
    }
}

void deal_value(void) {
    if (config.m_weight_config.m_auto_take_pic) {
        // 模式是重量增加模式，需要的是一个突然增加重量的过程，如果缓慢的重量增加或减小，就跟随。
        if (config.m_weight_config.m_control_mode == ConfigStruct::weight_config::ADD_WITH_PIC) {
            auto temp_class = std::dynamic_pointer_cast<RS485SerialPort<float>>(get_ptr("weight-reader"));
            if (temp_class == nullptr) {
                OUTPUT_ERRR << "weight-reader is nullptr" << std::endl;
                return;
            }
            static float real_pic_threshold = 0.0;
            static int wait_pic_time = 0;
            if (real_pic_threshold < 0.001 ||
                real_pic_threshold > temp_class->GetData()) {  // 当位于初次数据或重量在降低时，直接跟随
                real_pic_threshold = temp_class->GetData();
            } else if (
                fabs(real_pic_threshold - temp_class->GetData()) <=
                config.m_weight_config.m_permitted_data_fluctuations) {  // 当变化精度小于10.0g时，直接跟随数据的变动
                real_pic_threshold = temp_class->GetData();
            } else if (
                fabs(real_pic_threshold - temp_class->GetData()) >
                    config.m_weight_config.m_permitted_data_fluctuations &&
                fabs(real_pic_threshold - temp_class->GetData()) <=
                    config.m_weight_config
                        .m_min_add_step_weight) {  // 当变化精度大于10.0g但不稳定时，等待跟随数据的波动
                if (wait_pic_time < config.m_weight_config.m_over_permit_wait_period) {
                    wait_pic_time++;
                } else {
                    wait_pic_time = 0;
                    real_pic_threshold = temp_class->GetData();
                    send_capture_signal(temp_class->GetData());  // 要求拍照
                }
            } else if (temp_class->GetData() - real_pic_threshold > config.m_weight_config.m_min_add_step_weight) {
                wait_pic_time = 0;
                real_pic_threshold = temp_class->GetData();
                send_capture_signal(temp_class->GetData());  // 要求拍照
            }
        }
    }
    if (config.m_temperature_config.m_isopen && config.m_IO_controller_config.m_isopen) {
        auto IO_control_class = std::dynamic_pointer_cast<IO_Control>(get_ptr("IO-controller"));
        if (IO_control_class == nullptr) {
            OUTPUT_ERRR << "IO-controller is nullptr" << std::endl;
            return;
        }
        if (config.m_temperature_config.m_control_mode == ConfigStruct::temperature_config::KEEP_COLSE ||
            config.m_temperature_config.m_control_mode == ConfigStruct::temperature_config::KEEP_OPEN) {
            if (static_cast<bool>(
                    (IO_control_class->GetData() >>
                     static_cast<int>(config.m_temperature_config.m_bind_controller_func_index)) &
                    0x01) != config.m_temperature_config.m_open_to_output_state) {
                IO_control_class->SetCoilSwitch(
                    config.m_temperature_config.m_bind_controller_func_index,
                    config.m_temperature_config.m_open_to_output_state);
            }

        } else if (config.m_temperature_config.m_control_mode == ConfigStruct::temperature_config::AUTO_CONTROL) {
            auto temp_reader_class = std::dynamic_pointer_cast<RS485SerialPort<float>>(get_ptr("temperature-reader"));
            if (temp_reader_class->GetData() < config.m_temperature_config.m_temperature_Threshold_close) {
                /* 小于设定的关闭阈值，就进行关闭 */
                IO_control_class->SetCoilSwitch(
                    config.m_temperature_config.m_bind_controller_func_index,
                    !config.m_temperature_config.m_open_to_output_state);
            } else if (temp_reader_class->GetData() > config.m_temperature_config.m_temperature_Threshold_open) {
                /* 大于设定的打开阈值，就进行打开 */
                IO_control_class->SetCoilSwitch(
                    config.m_temperature_config.m_bind_controller_func_index,
                    config.m_temperature_config.m_open_to_output_state);
            } else {
                /* 大于关闭阈值，小于打开阈值，进行保持 */
            }
        }
    }
}

void save_log(void) {}

bool read_config() {
    configManager.loadConfig();
    config.read_config(configManager.getConfig());  // 将config读入structure
    // 获取数组中的第一个元素的 isopen
    if (configManager.getSafe<bool>("debug", false)) {
        OUPUT_INFO << "读取到当前需要打开数据接收调试输出" << std::endl;
        for (auto p_func : FuncList) {
            p_func->SetDebugModel(true);
        }
    }
    return true;
}

int main() {
    read_config();
    // 获取单例实例
    create_func_list();
    if (!init_dev()) {
        return 1;
    }
    while (true) {
        // 记录当前时间
        static std::chrono::steady_clock::time_point lastRecordedTime = std::chrono::steady_clock::now();
        // 判断是否超过 5 分钟（300 秒）
        if ((std::chrono::duration_cast<std::chrono::duration<double>>(
                 std::chrono::steady_clock::now() - lastRecordedTime))
                .count() > 300.0) {
            check_online();  // 检查设备是否在线
            lastRecordedTime = std::chrono::steady_clock::now();
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        read_data();
        print_value();
        deal_value();
    }
    return 0;
}